/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */

#ifndef MEMORYTEST_H_
#define MEMORYTEST_H_

#include "TestCase.h"
#include "Utils/Logging.h"
#include "Utils/CppExtensions.h"



class MemoryTest :  public TestCase<MemoryTest>
{
private:
	const prog_mem * testStr;

public:


	MemoryTest(const prog_mem * testMethodName, TestCase<MemoryTest>::TestMethod testMethod) :
	TestCase<MemoryTest>(testMethodName, testMethod), testStr(PROG_MEM_STRING("01234567890012345678900123456789001234567890"))
	{
	}

	bool callBack(const char * str)
	{

		const prog_mem * otherStr = PROG_MEM_STRING("Another string");
		char * string = new(Allocators::STACK) char[45];
		strcpy(string, otherStr);

		bool result =  AVRUNIT_ASSERT_EQUALS_STRING_TESTNAME_P(string, otherStr, "other string wrote");

		strcpy(string, str);

		return result & AVRUNIT_ASSERT_EQUALS_STRING_TESTNAME_P(string, testStr, "testString string wrote");

	}

	bool testnew_Allocators_STACK()
	{


		size_t initialStackSize = stackSize();

		char * string = new(Allocators::STACK) char[45];

		bool result = AVRUNIT_ASSERT_EQUALS_LONG_TESTNAME(stackSize(), initialStackSize + 45, "new(Allocators::STACK)");

		strcpy(string, testStr);


		result &= AVRUNIT_ASSERT_EQUALS_STRING_TESTNAME_P(string, testStr, "allocation string wrote");


		result &= callBack(string);

		result &= AVRUNIT_ASSERT_EQUALS_STRING_TESTNAME_P(string, testStr, "after callback");

		return result;
	}

	bool allocateMaxMemoryChunck()
	{
		uint8_t * STACK_PROVISION = new(Allocators::STACK) uint8_t[100]; // stack provision

		uint8_t * bytes = new uint8_t[maxMemoryChunkLeft()];

		bool result = !isNull(bytes);

		delete bytes;

		return result;

	}
	bool testnew()
	{
		const size_t mallocMarginExtra = 30; //TODO find out why

		size_t initialStackSize = stackSize();

		char * initialHeapTop =  (char*)getHeapTop();

		size_t initialDistanceHeapFromStack = distanceHeapFromStack();

		size_t initialmaxChunkLeft = maxMemoryChunkLeft();

		bool result = AVRUNIT_ASSERT_EQUALS_LONG(initialDistanceHeapFromStack, RAMEND - initialStackSize - (size_t)initialHeapTop);

		uint8_t * bytes = new uint8_t[4000];

		result &= AVRUNIT_ASSERT_AUTONAME(isNull(bytes));

		result &= AVRUNIT_ASSERT_EQUALS_LONG_TESTNAME(initialmaxChunkLeft, maxMemoryChunkLeft(), "maxMemoryChunkLeft");

		result &= AVRUNIT_ASSERT_AUTONAME(allocateMaxMemoryChunck());



		PRINT_MEMORY_STATUS();

		return result;
	}


};

#endif /* MEMORYTEST_H_ */
